package model;

import Interfaces.Ficha;

public class Variante {

	private final Pieza pieza;
	private final Ficha fichaVariada;
	private final int[][] indicaciones = new int[Pieza.CUADRADOS_POR_PIEZA-1][2];
	
	/**
	 * Representa la posible variación de una pieza del rompecabezas,
	 * la cual puede estar dada por girarla y/u orientarla de diferentes 
	 * maneras.
	 * @param pieza que se busca variar
	 * @param variator encargado de variar la ficha base de la pieza
	 */
	public Variante(final Pieza pieza, final Variator variator) {
		super();
		this.pieza = pieza;
		fichaVariada = variator.variate(pieza.getFicha());
		generateIndicaciones();
	}

	/**
	 * Crea el vector con los pares ordenados que funcionan como deltas
	 * para ubicar los cuadrados de la variante en el tablero.
	 */
	private void generateIndicaciones() {
		int refX = 0;
		int refY = 0;
		int i = 0;
		int x,y;
		boolean primeroEncontrado = false;
		// Para todas las filas,
		for (x = 0; x < fichaVariada.obtenerX(); x++) {
			// para todas las columnas,
			for (y = 0; y < fichaVariada.obtenerY(); y++) {
				assert i < Pieza.CUADRADOS_POR_PIEZA;
				// si todavía no encontré un cuadrado ocupado,
				if (primeroEncontrado) {
					// si la ficha en esta posición tiene un cuadrado,
					if (fichaVariada.valor(x, y)) {
						// guardo el par ordenado como referencia.
						indicaciones[i][0] = x - refX; 
						indicaciones[i][1] = y - refY;
						// y marco que se guardó otra indicación.
						i++;
					}
				// pero si todavía no lo encontré el primero,
				} else {
					// hay que buscarlo.
					if (fichaVariada.valor(x, y)) {
						refX = x; 
						refY = y;
						primeroEncontrado = true;
					}
				}
			}
		}
	}

	public Ficha getFichaVariada() {
		return fichaVariada;
	}

	public Pieza getPieza() {
		return pieza;
	}

	public int[][] getIndicaciones() {
		return indicaciones;
	}
	
	/**
	 * Compara las fichas que se han variado al crear la variante.
	 * De tener los mismos valores, se entiende que se trata de la 
	 * misma variante de la pieza.
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Variante) {
			final Variante other = (Variante) obj;
			final Ficha otherFicha = other.getFichaVariada();
			if (fichaVariada.obtenerX() == otherFicha.obtenerX()
					&& fichaVariada.obtenerY() == otherFicha.obtenerY()) {
				for (int x = 0; x < fichaVariada.obtenerX(); x++) {
					for (int y = 0; y < fichaVariada.obtenerY(); y++) {
						if (fichaVariada.valor(x, y) != otherFicha.valor(x, y)) {
							return false;
						}
					}
				}
				return true;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		return fichaVariada.getNombre().hashCode();
	}

	@Override
	public String toString() {
		final StringBuffer buffer = new StringBuffer();
		for (int x = 0; x < fichaVariada.obtenerX(); x++) {
			for (int y = 0; y < fichaVariada.obtenerY(); y++) {
				buffer.append(fichaVariada.valor(x, y) ? 
						fichaVariada.getNombre() : " ");	
			}
			buffer.append("\n");
		}
		return buffer.toString();
	}
	
}
